package user.view;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.text.JTextComponent;

import model.doe.GaussLaguerreModan;
import model.util.FourerExecutor;
import model.util.FourerExecutor.DoeType;
import system.activity.MainListener;
import system.elements.ControlTextField;
import system.util.PlotBuilder;
import static org.math.array.DoubleArray.*;
public class GLModanImpl extends Controls
{

	private javax.swing.JCheckBox amplitude;
	private javax.swing.JButton cancelButton;
	private javax.swing.JLabel firstParam;
	private ControlTextField firstParamText;
	private javax.swing.JLabel height;
	private ControlTextField heightText;
	private javax.swing.JButton okButton;
	private javax.swing.JCheckBox phase;
	private javax.swing.JLabel radius;
	private ControlTextField radiusText;
	private javax.swing.JLabel secondParam;
	private ControlTextField secondParamText;
	private javax.swing.JLabel step;
	private ControlTextField stepText;
	private javax.swing.JLabel width;
	private ControlTextField widthText;
	private javax.swing.JCheckBox fourer;

	public GLModanImpl(final MainListener listener)
	{
		this.listener = listener;
		this.setLayout(new java.awt.BorderLayout());

		init();
	}

	public GLModanImpl(final MainListener listener, ArrayList<String> params)
	{
		this.listener = listener;
		this.setLayout(new java.awt.BorderLayout());
		initFromHistory(params);
	}
	
	@Override
	protected LinkedList<JTextComponent> elementsQueue()
	{
		LinkedList<JTextComponent> result = new LinkedList<JTextComponent>();
		result.add(stepText);
		result.add(widthText);
		result.add(heightText);
		result.add(radiusText);
		result.add(firstParamText);
		result.add(secondParamText);
		return result;
	}
	
	@Override
	protected void init()
	{
		step = new javax.swing.JLabel();
		width = new javax.swing.JLabel();
		height = new javax.swing.JLabel();
		radius = new javax.swing.JLabel();
		firstParam = new javax.swing.JLabel();
		secondParam = new javax.swing.JLabel();
		stepText = new ControlTextField();
		widthText = new ControlTextField();
		heightText = new ControlTextField();
		radiusText = new ControlTextField();
		firstParamText = new ControlTextField();
		secondParamText = new ControlTextField();
		amplitude = new javax.swing.JCheckBox();
		phase = new javax.swing.JCheckBox();
		okButton = new javax.swing.JButton();
		cancelButton = new javax.swing.JButton();
		fourer = new JCheckBox();
		
		fourer.setText("Выполнить преобразование Фурье");
		fourer.setEnabled(false);
		
		amplitude.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				checkFourerAvailable();
			}

		});
		phase.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				checkFourerAvailable();
			}

		});
		step.setText("Шаг дискретизации"); // NOI18N
		step.setName("step"); // NOI18N

		width.setText("Ширина"); // NOI18N
		width.setName("width"); // NOI18N

		height.setText("Высота"); // NOI18N
		height.setName("height"); // NOI18N

		radius.setText("Радиус"); // NOI18N
		radius.setName("radius"); // NOI18N

		firstParam.setText("N1"); // NOI18N
		firstParam.setName("firstParam"); // NOI18N

		secondParam.setText("N2"); // NOI18N
		secondParam.setName("secondParam"); // NOI18N

		stepText.setText("1"); // NOI18N
		stepText.setName("stepText"); // NOI18N

		widthText.setText("512"); // NOI18N
		widthText.setName("widthText"); // NOI18N

		heightText.setText("512"); // NOI18N
		heightText.setName("heightText"); // NOI18N

		radiusText.setText("100"); // NOI18N
		radiusText.setName("radiusText"); // NOI18N

		firstParamText.setText("0"); // NOI18N
		firstParamText.setName("firstParamText"); // NOI18N

		secondParamText.setText("0"); // NOI18N
		secondParamText.setName("secondParamText"); // NOI18N

		amplitude.setText("Расчет амплитуды"); // NOI18N
		amplitude.setName("amplitude"); // NOI18N

		phase.setText("Расчет знака фазы"); // NOI18N
		phase.setName("phase"); // NOI18N

		okButton.setText("Рассчитать"); // NOI18N
		okButton.setName("okButton"); // NOI18N

		cancelButton.setText("Закрыть"); // NOI18N
		cancelButton.setName("cancelButton"); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(phase)
                    .addComponent(amplitude)
                    .addComponent(fourer)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(okButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(cancelButton))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addComponent(secondParam, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(firstParam, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(step, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(width, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(height, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(radius, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(firstParamText, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(radiusText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(heightText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(widthText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(stepText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE)
                            .addComponent(secondParamText, javax.swing.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE))))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(step)
                    .addComponent(stepText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(width)
                    .addComponent(widthText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(height)
                    .addComponent(heightText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(radius)
                    .addComponent(radiusText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(firstParam)
                    .addComponent(firstParamText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(secondParam)
                    .addComponent(secondParamText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(16, 16, 16)
                .addComponent(amplitude)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(phase)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(fourer)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 90, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(okButton)
                    .addComponent(cancelButton))
                .addContainerGap())
        );

		okButton.addMouseListener(new java.awt.event.MouseAdapter()
		{
			public void mouseClicked(java.awt.event.MouseEvent evt)
			{
				try {
					okButton.setEnabled(false);
					final GaussLaguerreModan modan = new GaussLaguerreModan(Double.parseDouble(widthText.getText()), Double.parseDouble(heightText.getText()),
							Double.parseDouble(stepText.getText()), Double.parseDouble(radiusText.getText()), Integer.parseInt(firstParamText.getText()),
							Integer.parseInt(secondParamText.getText()));
					listener.clearImagePanel();
					listener.setLoadStatus();
					java.awt.event.ActionListener actionListener = new java.awt.event.ActionListener()
					{
						public void actionPerformed(java.awt.event.ActionEvent actionEvent)
						{
							try {
								if (amplitude.isSelected()) {
									double[][] z = modan.getAbsoluteAmplitudeMatrix();
									double[] x = increment(0d, 1d, z[0].length);
									double[] y = increment(0d, 1d, z.length);
									String plotDescription = "Распределение амплитуды пучка Лагерра-Гаусса";
									listener.addImagePanel(modan.getAbsoluteAmplitudeImage(),"Распределение амплитуды");
									listener.addFastPlotPanel(PlotBuilder.buildFast3DPlot(x, y, z, plotDescription), "Распределение амплитуды - график");
									onResize();
									listener.needRepaint();
								}
								if (phase.isSelected()) {
									listener.addImagePanel(modan.getSignPhaseImage(),"Распределение знака фазы");
									onResize();
									listener.needRepaint();
								}
								if (phase.isSelected() && amplitude.isSelected() && fourer.isSelected()) {
									FourerExecutor fourer = new FourerExecutor();
									ArrayList<BufferedImage> fourerImages = fourer.fft(modan, DoeType.AMPLITUDE);
									listener.addImagePanel(fourerImages.get(0),"Распредление амплитуды после преобразования Фурье");
									
									double[][] z = fourer.getResultAmpl();
									double[] x = increment(0d, 1d, z[0].length);
									double[] y = increment(0d, 1d, z.length);
									String plotDescription = "Распределение амплитуды пучка Лагерра-Гаусса";
									listener.addFastPlotPanel(PlotBuilder.buildFast3DPlot(x, y, z, plotDescription), "Распределение амплитуды после преобразования Фурье - график");
									
									
									listener.addImagePanel(fourerImages.get(1),"Распредление знака фазы после преобразования Фурье");
									onResize();
									listener.needRepaint();
								}
								listener.removeLoadStatus();
								okButton.setEnabled(true);
							} catch (OutOfMemoryError ex) {
								listener.removeLoadStatus();
								okButton.setEnabled(true);
								listener.showErrorMessage("Перепелнение памяти");
							}
							catch(IllegalArgumentException ex)
							{
								listener.removeLoadStatus();
								okButton.setEnabled(true);
								listener.showErrorMessage(ex.getMessage());
							}
						}
					};
					Timer timer = new Timer(500, actionListener);
					timer.setRepeats(false);
					timer.start();
				} catch (NumberFormatException ex) {
					listener.showErrorMessage("Ошибка формата входных данных");
					listener.removeLoadStatus();
					okButton.setEnabled(true);
				}
			}
		});
		cancelButton.addMouseListener(new java.awt.event.MouseAdapter()
		{
			public void mouseClicked(java.awt.event.MouseEvent evt)
			{
				listener.removeLeftPanel();
				onResize();
				listener.needRepaint();
			}
		});
		Border border = BorderFactory.createEtchedBorder(Color.white, new Color(178, 178, 178));
		this.setBorder(border);
		listener.addPanel(this);
		this.show();
	}

	void onResize()
	{
		this.show();
	}

	@Override
	public void setListener(MainListener listener)
	{
		this.listener = listener;
	}

	@Override
	public Collection<String> getControlsValues()
	{
		Date date = new Date();
		Collection<String> result = new ArrayList<String>();
		result.add("                                                                        " + date.getHours() + ":" + date.getMinutes() + ":"
				+ date.getSeconds() + "   " + date.getDate() + "." + (date.getMonth() + 1) + "." + (date.getYear() + 1900));
		result.add("Моделирование пучков Лагерра-Гаусса");
		result.add("Введенные параметры:");
		result.add("N1 = " + firstParamText.getText());
		result.add("N2 = " + secondParamText.getText());
		result.add("Радиус = " + radiusText.getText());
		result.add("Высота = " + heightText.getText());
		result.add("Ширина = " + widthText.getText());
		result.add("Шаг дискретизация = " + stepText.getText());
		result.add("");
		return result;
	}

	@Override
	String getClassName()
	{
		return this.getClass().getCanonicalName();
	}
	private void checkFourerAvailable() {
		fourer.setEnabled(amplitude.isSelected() && phase.isSelected());
		if(fourer.isEnabled() == false)
		{
			fourer.setSelected(false);
		}
	}
}
